;;;; Defines the EVPL lexer.
;;;; Copyright (C) 2009 David J. Rosenbaum, email: davidjrosenbaum@comcast.net
;;;;
;;;; This program is free software: you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation, under version 3 of the License.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;;;;
;;;; Copyright (C) 2009 David J. Rosenbaum
;;;; This program comes with ABSOLUTELY NO WARRANTY; for details see COPYING.
;;;; This is free software, and you are welcome to redistribute it
;;;; under certain conditions; for details see COPYING.

(in-package :evpl)

(defparameter *delimiters* '((|{| . |}|) (|[| . |]|) (|(| . |)|))
  "The delimiters used by EVPL.  The car of each cons is the opening delimiter and the cdr is the corresponding closing
delimiter.")

(defun opening-delimiter-p (symbol)
  "Returns symbol if symbol is an opening delimiter; otherwise nil is returned."
  (member symbol *delimiters* :key #'car))

(defun closing-delimiter-p (symbol)
  "Returns symbol if symbol is an closing delimiter; otherwise nil is returned."
  (member symbol *delimiters* :key #'cdr))

(cl-lex:define-string-lexer string-lexer
  ("function|variable|let|foreach|in|while|if|else|return|true|false|<-|\\^|[*/%+\\-]|is|=|<=|>=|<|>|{|}|\\[|\\]|\\(|\\)|and|or|xor|not|:=|,|;"
   (let ((symbol (intern (string-upcase $@) :evpl)))
     (return (values symbol (case symbol
			      (true t)
			      (false nil)
			      (^ 'expt)
			      (% 'mod)
			      (is 'eql)
			      (= 'equal)
			      (t symbol))))))
  ("[a-zA-Z][a-zA-Z0-9_]*" (return (values 'identifier (intern $@ :evpl.identifiers))))
  ("([0-9]*\\.[0-9]+(e[+-]?[0-9]+)?)|([0-9]+e[+-]?[0-9]+)" (return (values 'float (read-from-string $@))))
  ("-?[0-9]+/[1-9][0-9]*" (return (values 'rational (read-from-string $@))))
  ("-?[0-9]+" (return (values 'integer (read-from-string $@))))
  ("\"[^\"]*\"" (return (values 'string (subseq $@ 1 (1- (length $@))))))
  ";.*(\\n|$)"
  "[ \\t\\n]"
  ("." (cerror "Skip to the next lexeme" 'unknown-character :character (char $@ 0))))
